package yunjiao.javatutorials.guava.concurrent.comprehensive;

import yunjiao.javatutorials.guava.concurrent.ForwardingCondition;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;

/**
 * 组合条件
 *
 * @author yangyunjiao
 */
public class ComprehensiveCondition extends ForwardingCondition {
    private final Condition delegate;

    // 统计计数器
    private final AtomicInteger waitCount = new AtomicInteger(0);
    private final AtomicInteger signalCount = new AtomicInteger(0);
    private final AtomicInteger signalAllCount = new AtomicInteger(0);
    private final AtomicInteger timeoutCount = new AtomicInteger(0);
    private final AtomicInteger interruptCount = new AtomicInteger(0);

    // 时间统计
    private final AtomicLong totalWaitTime = new AtomicLong(0);
    private final AtomicLong maxWaitTime = new AtomicLong(0);
    private final AtomicLong minWaitTime = new AtomicLong(Long.MAX_VALUE);

    public ComprehensiveCondition(Condition delegate) {
        this.delegate = delegate;
    }

    @Override
    protected Condition delegate() {
        return delegate;
    }

    @Override
    public void await() throws InterruptedException {
        long startTime = System.nanoTime();
        waitCount.incrementAndGet();

        try {
            System.out.printf("[ComprehensiveCondition] 开始等待 - 总等待次数: %d%n", waitCount.get());
            super.await();
        } catch (InterruptedException e) {
            interruptCount.incrementAndGet();
            System.out.printf("[ComprehensiveCondition] 等待被中断 - 总中断次数: %d%n", interruptCount.get());
            throw e;
        } finally {
            long duration = System.nanoTime() - startTime;
            updateTimeStatistics(duration);
            System.out.printf("[ComprehensiveCondition] 等待完成 - 耗时: %d ns%n", duration);
        }
    }

    @Override
    public boolean await(long time, TimeUnit unit) throws InterruptedException {
        long startTime = System.nanoTime();
        waitCount.incrementAndGet();

        try {
            System.out.printf("[ComprehensiveCondition] 开始带超时等待 (%d %s) - 总等待次数: %d%n",
                    time, unit, waitCount.get());

            boolean result = super.await(time, unit);

            if (!result) {
                timeoutCount.incrementAndGet();
                System.out.printf("[ComprehensiveCondition] 等待超时 - 总超时次数: %d%n", timeoutCount.get());
            }

            return result;
        } catch (InterruptedException e) {
            interruptCount.incrementAndGet();
            System.out.printf("[ComprehensiveCondition] 带超时等待被中断 - 总中断次数: %d%n", interruptCount.get());
            throw e;
        } finally {
            long duration = System.nanoTime() - startTime;
            updateTimeStatistics(duration);
            System.out.printf("[ComprehensiveCondition] 带超时等待完成 - 耗时: %d ns%n", duration);
        }
    }

    @Override
    public long awaitNanos(long nanosTimeout) throws InterruptedException {
        long startTime = System.nanoTime();
        waitCount.incrementAndGet();

        try {
            System.out.printf("[ComprehensiveCondition] 开始纳秒级等待 (%d ns) - 总等待次数: %d%n",
                    nanosTimeout, waitCount.get());

            long remaining = super.awaitNanos(nanosTimeout);

            if (remaining <= 0) {
                timeoutCount.incrementAndGet();
                System.out.printf("[ComprehensiveCondition] 纳秒等待超时 - 总超时次数: %d%n", timeoutCount.get());
            }

            return remaining;
        } catch (InterruptedException e) {
            interruptCount.incrementAndGet();
            System.out.printf("[ComprehensiveCondition] 纳秒等待被中断 - 总中断次数: %d%n", interruptCount.get());
            throw e;
        } finally {
            long duration = System.nanoTime() - startTime;
            updateTimeStatistics(duration);
            System.out.printf("[ComprehensiveCondition] 纳秒等待完成 - 耗时: %d ns%n", duration);
        }
    }

    @Override
    public void awaitUninterruptibly() {
        long startTime = System.nanoTime();
        waitCount.incrementAndGet();

        System.out.printf("[ComprehensiveCondition] 开始不可中断等待 - 总等待次数: %d%n", waitCount.get());

        super.awaitUninterruptibly();

        long duration = System.nanoTime() - startTime;
        updateTimeStatistics(duration);
        System.out.printf("[ComprehensiveCondition] 不可中断等待完成 - 耗时: %d ns%n", duration);
    }

    @Override
    public void signal() {
        signalCount.incrementAndGet();
        System.out.printf("[ComprehensiveCondition] 发送信号 - 总信号次数: %d, 总等待次数: %d%n",
                signalCount.get(), waitCount.get());
        super.signal();
    }

    @Override
    public void signalAll() {
        signalAllCount.incrementAndGet();
        System.out.printf("[ComprehensiveCondition] 广播信号 - 总广播次数: %d, 总等待次数: %d%n",
                signalAllCount.get(), waitCount.get());
        super.signalAll();
    }

    private void updateTimeStatistics(long duration) {
        totalWaitTime.addAndGet(duration);

        // 更新最大等待时间
        long currentMax;
        do {
            currentMax = maxWaitTime.get();
            if (duration <= currentMax) break;
        } while (!maxWaitTime.compareAndSet(currentMax, duration));

        // 更新最小等待时间
        long currentMin;
        do {
            currentMin = minWaitTime.get();
            if (duration >= currentMin) break;
        } while (!minWaitTime.compareAndSet(currentMin, duration));
    }

    // 统计获取方法
    public int getWaitCount() {
        return waitCount.get();
    }

    public int getSignalCount() {
        return signalCount.get();
    }

    public int getSignalAllCount() {
        return signalAllCount.get();
    }

    public int getTotalSignalCount() {
        return signalCount.get() + signalAllCount.get();
    }

    public int getTimeoutCount() {
        return timeoutCount.get();
    }

    public int getInterruptCount() {
        return interruptCount.get();
    }

    public long getTotalWaitTime() {
        return totalWaitTime.get();
    }

    public double getAverageWaitTime() {
        int count = waitCount.get();
        return count == 0 ? 0 : (double) totalWaitTime.get() / count;
    }

    public long getMaxWaitTime() {
        return maxWaitTime.get() == Long.MAX_VALUE ? 0 : maxWaitTime.get();
    }

    public long getMinWaitTime() {
        return minWaitTime.get() == Long.MAX_VALUE ? 0 : minWaitTime.get();
    }

    public double getTimeoutRate() {
        int count = waitCount.get();
        return count == 0 ? 0 : (double) timeoutCount.get() / count;
    }

    public double getInterruptRate() {
        int count = waitCount.get();
        return count == 0 ? 0 : (double) interruptCount.get() / count;
    }

    public double getSignalToWaitRatio() {
        int waitCount = this.waitCount.get();
        return waitCount == 0 ? 0 : (double) getTotalSignalCount() / waitCount;
    }

    // 重置统计
    public void resetStatistics() {
        waitCount.set(0);
        signalCount.set(0);
        signalAllCount.set(0);
        timeoutCount.set(0);
        interruptCount.set(0);
        totalWaitTime.set(0);
        maxWaitTime.set(0);
        minWaitTime.set(Long.MAX_VALUE);
        System.out.println("[ComprehensiveCondition] 所有统计信息已重置");
    }

    // 打印详细统计
    public void printDetailedStatistics() {
        System.out.println("\n" + "=".repeat(60));
        System.out.println("        COMPREHENSIVE CONDITION 详细统计报告");
        System.out.println("=".repeat(60));

        System.out.printf("等待统计:%n");
        System.out.printf("  - 总等待次数: %,d%n", getWaitCount());
        System.out.printf("  - 超时次数: %,d (%.2f%%)%n", getTimeoutCount(), getTimeoutRate() * 100);
        System.out.printf("  - 中断次数: %,d (%.2f%%)%n", getInterruptCount(), getInterruptRate() * 100);

        System.out.printf("%n信号统计:%n");
        System.out.printf("  - 单播信号次数: %,d%n", getSignalCount());
        System.out.printf("  - 广播信号次数: %,d%n", getSignalAllCount());
        System.out.printf("  - 总信号次数: %,d%n", getTotalSignalCount());
        System.out.printf("  - 信号/等待比例: %.2f%n", getSignalToWaitRatio());

        System.out.printf("%n时间统计 (纳秒):%n");
        System.out.printf("  - 总等待时间: %,d ns%n", getTotalWaitTime());
        System.out.printf("  - 平均等待时间: %,.2f ns%n", getAverageWaitTime());
        System.out.printf("  - 最大等待时间: %,d ns%n", getMaxWaitTime());
        System.out.printf("  - 最小等待时间: %,d ns%n", getMinWaitTime());

        if (getWaitCount() > 0) {
            System.out.printf("%n性能指标:%n");
            double avgMs = getAverageWaitTime() / 1_000_000.0;
            System.out.printf("  - 平均等待时间: %.3f ms%n", avgMs);

            long totalMs = getTotalWaitTime() / 1_000_000;
            System.out.printf("  - 累计等待时间: %d ms%n", totalMs);
        }

        System.out.println("=".repeat(60));
    }

    // 生成统计摘要（适合日志记录）
    public String getStatisticsSummary() {
        return String.format(
                "ComprehensiveConditionStats{waits=%d, signals=%d, timeouts=%d, interrupts=%d, avgWait=%.2fns}",
                getWaitCount(), getTotalSignalCount(), getTimeoutCount(), getInterruptCount(), getAverageWaitTime()
        );
    }
}
